package fun.symtable;

import fun.parser.ast.node.base.Expression;
import fun.symtable.system.Function;
import fun.symtable.system.abs;
import fun.symtable.system.ceil;
import fun.symtable.system.floor;
import fun.symtable.system.max;
import fun.symtable.system.min;
import fun.symtable.system.pow;
import fun.symtable.system.ran;
import fun.symtable.system.round;
import fun.symtable.system.sqrt;
import fun.symtable.system.log.exp;
import fun.symtable.system.log.ln;
import fun.symtable.system.log.log;
import fun.symtable.system.log.log10;
import fun.symtable.system.log.log2;
import fun.symtable.system.trig.acos;
import fun.symtable.system.trig.asin;
import fun.symtable.system.trig.atan;
import fun.symtable.system.trig.cos;
import fun.symtable.system.trig.cosh;
import fun.symtable.system.trig.cot;
import fun.symtable.system.trig.sin;
import fun.symtable.system.trig.sinh;
import fun.symtable.system.trig.tan;
import fun.symtable.system.trig.tanh;

public class SystemSymbolTable {
    private static final UnmodifiableSymbolTable table;
    static {
	table = new UnmodifiableSymbolTable("System");
	// add constant
	table.internlAddVariable("pi", 3.141592653589793238462643383279502884197169399375105820974944592);
	table.internlAddVariable("e", 2.718281828459045235360287471352662497757247093699959574966967628);
	// simple
	table.internalAddFunctions(new abs(), new ceil(), new floor(), new max(), new min(), new pow(), new ran(),
		new round(), new sqrt());
	// log
	table.internalAddFunctions(new exp(), new ln(), new log(), new log10(), new log2());
	// trig
	table.internalAddFunctions(new acos(), new asin(), new atan(), new cos(), new cosh(), new cot(), new sin(),
		new sinh(), new tan(), new tanh());
    }

    private SystemSymbolTable() {
    }

    public static SymbolTable getInstance() {
	return table;
    }

    // ֻ����SymbolTable�����ṩ�������޸�(��ӣ�ɾ��ȵ�)����
    static class UnmodifiableSymbolTable extends DefaultSymbolTable {

	UnmodifiableSymbolTable(String name) {
	    super(name);
	}

	// �Ƿ�Ҫ�׳��쳣�أ�
	@Override
	public FunctionEntry setFunction(String name, String[] parameters, Expression expr) {
	    return null;
	}

	@Override
	public VariableEntry setVariable(String name, double value) {
	    return null;
	}

	@Override
	public void setParent(SymbolTable parent) {
	}

	// =========================================
	void internalAddFunctions(Function... functions) {
	    if (null == functions)
		return;
	    for (Function f : functions)
		this.internalAddFunction(f);
	}

	void internalAddFunction(Function fun) {
	    String name = fun.getFunctionName();
	    String[] args = fun.getArguments();
	    Expression exp = fun.getExpression();
	    this.internalAddFunction(name, args, exp);
	}

	void internalAddFunction(String name, String[] parameters, Expression expr) {
	    super.setFunction(name, parameters, expr);
	}

	void internlAddVariable(String name, double value) {
	    super.setVariable(name, value);
	}
    }
}
